﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Forms;

using DotNetLib.Windows.Forms;

using ExtensibleEventViewer.Console.Adapters;
using ExtensibleEventViewer.Console.DomainModel;
using ExtensibleEventViewer.Console.EventArguments;
using ExtensibleEventViewer.Console.Helpers;
using ExtensibleEventViewer.Console.Tasks;
using ExtensibleEventViewer.Core.Interfaces;
using ExtensibleEventViewer.Core.Primitives;


namespace ExtensibleEventViewer.Console.Forms
{
	public partial class MainWnd : Form
	{
		public MainWnd()
		{
			InitializeComponent();
		}

		protected override void OnLoad(EventArgs e)
		{
			if (AppSettings.Instance.EventLogsToMonitor != null)
			{
				LoadTrackedEventLogsTask task = new LoadTrackedEventLogsTask(UpdateEventLogList,
				                                                             AppSettings.Instance.EventLogsToMonitor);

				task.ExecuteOn = DateTime.UtcNow.AddSeconds(3);

				TaskService.Instance.AddTask(task);

				SetEnableAutoRefreshMenuItemText(AppSettings.Instance.EnableAutoRefresh);
			}

			EventLogMenuHelper.Instance.BindContextMenu(eventListContextMenu);

			base.OnLoad(e);
		}

		private void MainMenuButtonClick(object sender, Skybound.Rebar.RebarButtonEventArgs e)
		{
			switch (e.Button.Name)
			{
				case "btnChangeMonitoredEventLogs":
					EventLogListWnd eventLogList = new EventLogListWnd(AppSettings.Instance.ComputerList,
																   AppSettings.Instance.EventLogProviders,
																   AppSettings.Instance.EventLogsToMonitor);

					eventLogList.SaveMonitoredEventLogList += SaveMonitoredEventLogList;

					eventLogList.ShowDialog(this);
					break;
				case "btnQuery":
					using(QueryEditorWnd queryEditor = new QueryEditorWnd())
					{
						queryEditor.ShowDialog(this);
					}
					break;
				case "btnNetwork":
					using (ComputerListWnd computerListWnd = new ComputerListWnd(AppSettings.Instance.ComputerList))
					{
						computerListWnd.SaveComputerList += PopulateComputerList;

						computerListWnd.ShowDialog(this);
					}
					break;
				case "btnAutoRefresh":
					RefreshAllEventLogs();
					break;
				case "btnSettings":
					using (SettingsWnd wnd = new SettingsWnd(AppSettings.Instance.EventLogFilters, AppSettings.Instance.EnabledEventLogFilters))
					{
						wnd.ShowDialog(this);
					}
					break;
			}
		}

		private void RefreshAllEventLogs()
		{
			foreach (ContainerListViewItem item in lvwEventList.Items)
			{
				if (item.Tag is EventLogAdapter)
				{
					EventLogAdapter adapter = (EventLogAdapter) item.Tag;

					if (adapter.Settings.EnableRefresh)
					{
						adapter.RefreshRecords();
					}
				}
			}
		}

		private void PopulateComputerList(IEnumerable<string> computers)
		{
			AppSettings.Instance.ComputerList = computers.ToArray();
		}

		private void UpdateEventLogList(IEnumerable<TrackedEventLog> monitoredEventLogs)
		{
			List<TrackedEventLog> eventLogs = new List<TrackedEventLog>(monitoredEventLogs);

			UpdateStatusLabel("Loading eventlog records...");

			if (lvwEventList.InvokeRequired)
			{
				Action updateList = () =>
				                    	{
				                    		FillEventLogRecordListView(lvwEventList.Items, eventLogs);
											CreateRefreshTask();
				                    	};

				lvwEventList.BeginInvoke(updateList);
			}
			else
			{
				FillEventLogRecordListView(lvwEventList.Items, eventLogs);
				CreateRefreshTask();
			}
		}

		private void CreateRefreshTask()
		{
			List<EventLogAdapter> adapters = new List<EventLogAdapter>();

			foreach (ContainerListViewItem item in lvwEventList.Items)
			{
				if (item.Tag is EventLogAdapter)
				{
					adapters.Add((EventLogAdapter) item.Tag);
				}
			}

			RefreshEventLogViewListTask task = new RefreshEventLogViewListTask(adapters);
			task.IsRescheduled = true;
			task.RescheduleInterval = new TimeSpan(0, 0, 2);

			TaskService.Instance.AddTask(task);
		}

		private void UpdateStatusLabel(string text)
		{
			lblStatus.Text = text;
		}

		private void SaveMonitoredEventLogList(IEnumerable<TrackedEventLog> monitoredEventLogs)
		{
			List<TrackedEventLog> eventLogs = new List<TrackedEventLog>(monitoredEventLogs);

			AppSettings.Instance.EventLogsToMonitor = eventLogs.ToArray();

			UpdateEventLogList(monitoredEventLogs);
		}

		private void FillEventLogRecordListView(ContainerListViewItemCollection collection, IEnumerable<TrackedEventLog> eventLogsToTrack)
		{
			lvwEventList.Items.Clear();

			List<ContainerListViewItem> eventLogRecords = new List<ContainerListViewItem>();

			foreach (TrackedEventLog eventLogEntity in eventLogsToTrack)
			{
				eventLogRecords.Clear();

				EventLogEntity eventLog = ConvertToEventLogEntity(eventLogEntity);

				if (eventLog == null)
				{
					continue;
				}

				EventLogAdapter eventLogItem = new EventLogAdapter(eventLog);

				if (AppSettings.Instance.AdapterSettings != null)
				{
					EventLogAdapterSettingsData data = (
					                                   	from item in AppSettings.Instance.AdapterSettings
					                                   	where item.EventLogEntityID == eventLog.GetHashCode()
					                                   	select item).FirstOrDefault();

					if (data != null)
					{
						eventLogItem.Settings = new EventLogAdapterSettings
						                        	{
						                        		EnableRefresh = data.EnableRefresh,
						                        		RefreshInterval = new TimeSpan(data.RefreshIntervalTicks),
						                        		UseDefaultRefreshInterval = data.UseDefaultRefreshInterval
						                        	};
					}
				}

				collection.Add(eventLogItem.ListViewItem);

				eventLogItem.RefreshRecords();
			}
		}

		private EventLogEntity ConvertToEventLogEntity(TrackedEventLog eventLog)
		{
			IEventLogProvider provider = GetEventLogProviderByID(eventLog.ProviderID);

			if (provider == null)
			{
				return null;
			}

			EventLogConnector connector = new EventLogConnector(eventLog.ComputerName, provider);

			return connector.GetEventLog(eventLog.EventLogName);
		}

		private IEventLogProvider GetEventLogProviderByID(string providerID)
		{
			foreach (IEventLogProvider provider in AppSettings.Instance.EventLogProviders)
			{
				if(string.Equals(providerID,  provider.ProviderID, StringComparison.InvariantCultureIgnoreCase))
				{
					return provider;
				}
			}

			return null;
		}

		private EventLogRecordDetailsWnd detailsWnd;

		private void EventListDoubleClick(object sender, EventArgs e)
		{
			MouseEventArgs mouseEventArgs = (MouseEventArgs)e;

			if (mouseEventArgs.Button == MouseButtons.Left)
			{
				if (lvwEventList.SelectedItems.Count > 0)
				{
					if (lvwEventList.SelectedItems[0].Tag is EventLogRecordAdapter)
					{
						if (detailsWnd == null)
						{
							detailsWnd = new EventLogRecordDetailsWnd();
							detailsWnd.HideOnClose = true;
						}

						EventLogRecordAdapter recordAdapter = (EventLogRecordAdapter)lvwEventList.SelectedItems[0].Tag;
						EventLogAdapter eventLogAdapter = (EventLogAdapter)recordAdapter.ListViewItem.ParentItem.Tag;

						detailsWnd.ShowEventLogRecordDetails(eventLogAdapter.DataItem.Name, recordAdapter.DataItem, null);

						if (!detailsWnd.Visible)
						{
							detailsWnd.Show(this);
						}
					}
				}
			}
			else
			{
			}
		}

		protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
		{
			if (detailsWnd != null)
			{
				detailsWnd.Close();
				detailsWnd.Dispose();
			}

			base.OnClosing(e);
		}

		private void SetRefreshIntervalClick(object sender, EventArgs e)
		{
			using (TimePeriodWnd timePeriodSettingsWnd = new TimePeriodWnd())
			{
				timePeriodSettingsWnd.SaveTimePeriod += SaveAutoRefreshSettings;
				
				timePeriodSettingsWnd.LoadData(AppSettings.Instance.RefreshTimeInterval, AppSettings.Instance.EnableAutoRefresh);
				timePeriodSettingsWnd.ShowDialog(this);
			}
		}

		private void SaveAutoRefreshSettings(object sender, SaveTimePeriodEventArgs eventArgs)
		{
			AppSettings.Instance.RefreshTimeInterval = eventArgs.TimePeriod;
			AppSettings.Instance.EnableAutoRefresh = eventArgs.EnableAutoRefresh;
		}

		private void miEnableRefresh_Click(object sender, EventArgs e)
		{
			AppSettings.Instance.EnableAutoRefresh = !AppSettings.Instance.EnableAutoRefresh;

			SetEnableAutoRefreshMenuItemText(AppSettings.Instance.EnableAutoRefresh);
		}

		private void SetEnableAutoRefreshMenuItemText(bool enableAutoRefresh)
		{
			miEnableRefresh.Text = enableAutoRefresh
						?
							"Disable auto refresh"
						:
							"Enable auto refresh";
		}

		private void AddComputerClick(object sender, EventArgs e)
		{
			using (AddComputerWnd addComputerWnd = new AddComputerWnd())
			{
				addComputerWnd.AddComputer += AddComputerClick;

				addComputerWnd.ShowDialog(this);
			}
		}

		private void AddComputerClick(string computerName)
		{
			string[] computerNames = new string[AppSettings.Instance.ComputerList.Length + 1];

			Array.Copy(AppSettings.Instance.ComputerList, computerNames, AppSettings.Instance.ComputerList.Length);
			computerNames[computerNames.Length - 1] = computerName;

			AppSettings.Instance.ComputerList = computerNames;
		}
	}
}